// hash模式实现
let _Vue = null

export default class VueRouter {
  static install (Vue) {
    // 1.判断当前插件是否已经被安装
    if (VueRouter.install.installed) return
    VueRouter.install.installed = true

    // 2.把vue构造函数记录到全局变量
    _Vue = Vue

    // 3.把创建vue实例的时候传入的router对象注入到vue实例上——使用混入 mixin 的方式，混入里面增加 beforeCreate 的方法
    _Vue.mixin({
      beforeCreate () {
        if (this.$options.router) { // vue实例执行；组件不执行，组件的$options不存在router属性
          _Vue.prototype.$router = this.$options.router
          this.$options.router.init()
        }
      }
    })
  }

  constructor (options) {
    console.log(window.location)
    this.options = options
    this.routeMap = {}
    this.data = _Vue.observable({
      current: window.location.hash.substr(1) || '/' // 存储当前的路由地址
    }) // 使用observable可以将对象转成响应式的对象
  }

  init () {
    this.createRouteMap()
    this.initComponents(_Vue)
    this.initEvent()
  }

  initEvent () {
    // 前进后退时url地址会更新，但是组件并不会更新，
    // 实际需要的是，找到地址栏中的地址对应的组件，并渲染出来
    // 利用 hashchange
    window.addEventListener('hashchange', () => {
      this.data.current = window.location.hash.substr(1)
    })
  }

  // 遍历所有的路由规则，把路由规则解析成键值对的形式存储到routeMap中
  createRouteMap () {
    this.options.routes.forEach(route => {
      this.routeMap[route.path] = route.component
    })
  }

  // 传入Vue构造函数是为了减少对外部的依赖
  initComponents (Vue) {
    Vue.component('router-link', {
      props: {
        to: String
      },
      // 运行时编译器的 Vue 构建版本 无法编译 因此使用render
      // template: '<a :href="to"><slot></slot></a>'
      render (h) {
        console.log(this.to)
        return h('a', {
          attrs: {
            href: `/#${this.to}`
          }
        }, [this.$slots.default]) // 获取默认插槽的内容
      }
    })

    const self = this
    Vue.component('router-view', {
      render (h) {
        // render 函数里的this不是指向Vue实例
        // 获取当前路由地址对应的路由组件，调用 h 函数把组件转为虚拟DOM返回
        // 获取当前路由对应的组件，当前地址改变后将更新对应的页面
        console.log(self.data.current)
        const component = self.routeMap[self.data.current]
        return h(component)
      }
    })
  }
}
